﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine;
using UnityEngine.Assertions;

namespace Nirvana
{

    public abstract class UIVariableBindBool : UIVariableBind
    {
        public enum BooleanLogic
        {
            /// <summary>
            /// 所有variables的值为true，才返回true
            /// </summary>
            And,
            /// <summary>
            /// 只要有一个variable的值为true，就返回true
            /// </summary>
            Or
        }

        public enum CompareMode
        {
            Less,
            LessEqual,
            Equal,
            Great,
            GreatEqual
        }

        [Serializable]
        class UIVariableRef
        {
            [VariableName(UIVariableType.Boolean, UIVariableType.Integer, UIVariableType.Float)]
            [SerializeField]
            private string variablename;
            [SerializeField]
            private CompareMode compareMode = CompareMode.Equal;
            [SerializeField]
            private int referenceInt;
            [SerializeField]
            private float referenceFloat;
            /// <summary>
            /// 反转
            /// </summary>
            [SerializeField]
            private bool reverse;
            private UIVariable m_uivariable;
            public string VariableName
            {
                get
                {
                    return variablename;
                } 
            }

            public UIVariable UIVariable
            {
                get
                {
                    return m_uivariable;
                }
                set
                {
                    m_uivariable = value;
                }
            }

            public bool IsCompare()
            {
                if(UIVariable == null)
                {
                    return false;
                }
                if(UIVariable.VariableType == UIVariableType.Boolean)
                {
                    bool result = UIVariable.GetBoolean();
                    return this.reverse ? !result: result;
                }

                if(UIVariable.VariableType == UIVariableType.Integer)
                {
                    var value = UIVariable.GetInteger();
                    bool result = false;
                    switch (compareMode)
                    {
                        case CompareMode.Less:
                            result = value < this.referenceInt;
                            break;
                        case CompareMode.LessEqual:
                            result = value <= this.referenceInt;
                            break;
                        case CompareMode.Equal:
                            result = value == this.referenceInt;
                            break;
                        case CompareMode.Great:
                            result = value > this.referenceInt;
                            break;
                        case CompareMode.GreatEqual:
                            result = value >= this.referenceInt;
                            break;
                    }
                    return this.reverse ? !result : result;
                }

                if (UIVariable.VariableType == UIVariableType.Float)
                {
                    var value = UIVariable.GetFloat();
                    bool result = false;
                    switch (compareMode)
                    {
                        case CompareMode.Less:
                            result = value < this.referenceFloat;
                            break;
                        case CompareMode.LessEqual:
                            result = value <= this.referenceFloat;
                            break;
                        case CompareMode.Equal:
                            result = value == this.referenceFloat;
                            break;
                        case CompareMode.Great:
                            result = value > this.referenceFloat;
                            break;
                        case CompareMode.GreatEqual:
                            result = value >= this.referenceFloat;
                            break;
                    }
                    return this.reverse ? !result : result;
                }
                return false;
            }
        }

        [Tooltip("The boolean Logic.")]
        [SerializeField]
        private BooleanLogic m_booleanLogic;
        [Tooltip("The Variables for calculate the boolean value.")]
        [SerializeField]
        private UIVariableRef[] variables;

        protected abstract void OnValueChanged();

        protected override void BindVariables()
        {
            if(this.variables != null)
            {
                foreach (var p in this.variables)
                {
                    Assert.IsNull<UIVariable>(p.UIVariable);
                    if (!string.IsNullOrEmpty(p.VariableName))
                    {
                        p.UIVariable = base.FindVariable(p.VariableName);
                        if(p.UIVariable == null)
                        {
                            Debug.LogFormat("{0} can not find a variable {1}", base.name, p.VariableName);
                        }
                        else
                        {
                            p.UIVariable.OnValueInitialized += this.OnValueChanged;
                            p.UIVariable.OnValueChanged += this.OnValueChanged;
                            p.UIVariable.Add(this);
                        }
                    }
                }
            }

            this.OnValueChanged();
        }

        protected override void UnbindVariables()
        {
            if(this.variables != null)
            {
                foreach (var p in this.variables)
                {

                    if (p.UIVariable != null)
                    {
                        p.UIVariable.OnValueInitialized -= this.OnValueChanged;
                        p.UIVariable.OnValueChanged -= this.OnValueChanged;
                        p.UIVariable.Remove(this);
                        p.UIVariable = null;
                    }
                }
            }
        }

        /// <summary>
        /// variables所有结果
        /// </summary>
        protected bool GetResult()
        {
            if (this.variables == null) return false;
            if(this.m_booleanLogic == BooleanLogic.And)
            {
                bool result = true;
                foreach(var p in this.variables)
                {
                    if (p != null) result = result && p.IsCompare();
                }
                return result;
            }
            else
            {
                bool result = false;
                foreach (var p in this.variables)
                {
                    if (p != null) result = result || p.IsCompare();
                }
                return result;
            }
        }


    }
}

